ゆるふわでJSを書いていてもできる!?React Nativeを使ってiOSアプリをつくってみた。
React Nativeとは、JavaScript(React)でiOSやAndroidのネイティブアプリを作成するフレームワークです。基本的なお作法はReactそのままですが、React Nativeで用意されている<View>
や<TextInput>
といったネイティブっぽいコンポーネントを使って構築します。
今回はいわゆる「側アプリ」のWebView部分を、iOSのSimulator.appなどで簡単に動作検証できるよう、指定したURLをWebViewで表示するだけのアプリをReact Nativeでゆるふわに作成してみました。
この記事で使ったバージョンは次の通りで、シミュレータでの起動までを扱います。
- Node.js: v12.4.0
- React Native: 0.59.8
- Expo: 33.0.7
下準備
公式ドキュメントを見ると「ウェブ由来の人はExpoツールを使いましょう」ということなので、まずはExpoをインストールを進めます(Node.jsはインストールされている前提です)。
参照:Getting Started · React Native
Expoはプロジェクトの作成やシミュレータの起動からビルドなどを担うもので、XcodeやAndroid Studioを使うことなく開発を進めることができるツールです。
参照:Expo
npmを使ってExpoをインストールします。
npm install -g expo-cli
またWebViewがReact Nativeのコアから外されるようなので、別途React Native WebViewをインストールしておきます。
npm install -S react-native-webview
プロジェクトの作成
インストールできたらプロジェクトを作成します。(コマンド中の「GawaApp」はプロジェクト名なので、任意の名前を入れてください)
expo init GawaApp
少し待つと、「Choose a template:」とスケルトンを作成するテンプレートの選択するように指示が出ます。今回はタブバーは使わないので、一番上の「Blank」を選択します。
続いて「Please enter a few initial configuration values.」ということで、ホームスクリーンで表示されるアプリの名前を、「The name of your app visible on the home screen」の部分に下線がある状態で入力してください。
? Please enter a few initial configuration values. Read more: https://docs.expo.io/versions/latest/workflow/configuration/ › 50% completed { "expo": { "name": "<The name of your app visible on the home screen>", "slug": "GawaApp" } }
入力してEnterキーを押すと、必要なモジュール類のインストールが始まりますので、少し待ちましょう。
To get started, you can type: cd GawaApp npm start
と表示されたらインストール終了です。
ビルド
表示されている通り、cd GawaApp
で「GawaApp」ディレクトリへ移動し、npm start
でプロジェクトのプレビューを開始します。
少し待つとブラウザでExpoのDevToolが立ち上がります。
左側に「Run on iOS simulator」という項目があるので、クリックするとSimulator.appが立ち上がり、Expoアプリのインストールと起動がなされます。(Simulator.appの起動が失敗することがあるので、あらかじめ立ち上げておいたほうがいいかも)
初めてExpoアプリを立ち上げた場合、『「Command + D」でいつでもこの画面に戻れるよ!』という説明があるので「Got it」をタップして進めると、テンプレートで作成したアプリがお目見えします。
ライブリロードになっているので、ディレクトリにある「App.js」を編集して保存すると、即座に書き換わります。
エラーが出た場合は、エラー部分を修正してCommand + Rでリロードできます。(同期がうまくいかないのか、何度かリロードが必要な場合があります)
側アプリをつくる
URLを入力してボタンをタップすると、モーダルが下からスライドインしつつ、WebViewでページを表示するコードは次の通りです。単純なものなので、1ファイルにまとめています。
import React from 'react'; import { WebView } from 'react-native-webview'; import { StyleSheet, Text, TextInput, View, Button, Modal, SafeAreaView, } from 'react-native'; export default class App extends React.Component { constructor(props) { super(props); this.state = { isShowWebView: false, accessURL: '', isLengthExists: false, } } toggleGoButton(text) { if (0 !== text.length) { this.setState({isLengthExists: true}); } else { this.setState({isLengthExists: false}); } this.setState({accessURL: text}); } toggleModalDisplay(visible) { this.setState({ isShowWebView: visible }); } render() { return ( <SafeAreaView style={styles.container}> <View style={[styles.viewURLInput]}> <TextInput autoCapitalize='none' keyboardType='url' placeholder='Enter URL' placeholderTextColor='#888888' returnKeyType='go' onSubmitEditing={(e) => this.toggleModalDisplay(!this.state.isShowWebView)} onChangeText={(text) => this.toggleGoButton(text)} clearButtonMode='while-editing' style={styles.viewURLInput__url} autoFocus={true} /> <View style={styles.viewURLInput__button}> <Button disabled={!this.state.isLengthExists} title='Go!' accessibilityLabel='Access to inputed URL' onPress={() => {this.toggleModalDisplay(!this.state.isShowWebView)}} /> </View> </View> <Modal style={styles.container} visible={this.state.isShowWebView} animationType='slide'> <SafeAreaView style={styles.viewModal}> <WebView source={{uri: this.state.accessURL}} useWebKit={true} /> <View style={styles.viewModal__aside}> <Button title='Close' onPress={() => {this.toggleModalDisplay(!this.state.isShowWebView)}} /> </View> </SafeAreaView> </Modal> </SafeAreaView> ); } } const styles = StyleSheet.create({ container: { flex: 1, }, viewURLInput: { flex: 1, justifyContent: 'center', alignItems: 'stretch', padding: 16, }, viewURLInput__url: { textAlign: 'left', borderBottomWidth: 1, paddingVertical: 8, }, viewURLInput__button: { top: 16, }, viewModal: { flex: 1, }, viewModal__aside: { paddingBottom: 24, }, });
とりあえず動くようになったコードなので、ピヨピヨしていると思いますが…そこは何卒。
Viewの部分で使ったコンポーネントは、
- StyleSheet
- Text
- TextInput
- View
- Button
- Modal
- SafeAreaView
- WebView
で、おおよそ名前でどのような役割なのかは想像がつくのではないかと思います。
中でもStyleSheetは、コンポーネントのスタイルをHTMLのスタイルシートのように記述できるコンポーネントです。レイアウトにはFlexboxを使いますが、少し書き方がCSSのそれとは若干異なります。例えば、
- Flexboxを適用するには
display: flex
ではなくflex: 1
flexDirection
のデフォルトはcolumn
(=縦に並ぶ)
などなど、詳しくはドキュメントを参照してください。普通(?)のCSSに馴染んでいると挙動が謎いです……
- ドキュメント:Getting Started · React Native
- Flexboxについて:Layout with Flexbox · React Native
- レイアウトで使えるプロパティ:Layout Props · React Native
あと、WebViewで表示しようとしているページが、オレオレ証明書など使っている「https」だとATS(App Transport Security)のおかげでエラーが出ます(React Nativeだけでできる回避方法がわからなかったので、だれか詳しい人)。
雰囲気でJavaScriptを書いている私でも、これぐらいのアプリであればドキュメントを参照しながらつくることができました。
ぜひ試してみてくださいね!